/**
 * Copyright (c) 2008, Andrew Carter
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are 
 * permitted provided that the following conditions are met:
 * 
 * Redistributions of source code must retain the above copyright notice, this list of 
 * conditions and the following disclaimer. Redistributions in binary form must reproduce 
 * the above copyright notice, this list of conditions and the following disclaimer in 
 * the documentation and/or other materials provided with the distribution. Neither the 
 * name of Andrew Carter nor the names of contributors may be used to endorse or promote 
 * products derived from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.acarter.scenemonitor.propertydescriptor.definitions;


import com.acarter.propertytable.Property;
import com.acarter.propertytable.PropertySection;
import com.acarter.propertytable.PropertySectionState;
import com.acarter.propertytable.PropertyTable;
import com.acarter.propertytable.propertyobject.BooleanPropertyObject;
import com.acarter.propertytable.propertyobject.EnumPropertyObject;
import com.acarter.propertytable.propertyobject.FloatPropertyObject;
import com.acarter.propertytable.propertyobject.BooleanPropertyObject.I_BooleanPropertyObjectListener;
import com.acarter.propertytable.propertyobject.EnumPropertyObject.I_EnumPropertyObjectListener;
import com.acarter.propertytable.propertyobject.FloatPropertyObject.I_FloatPropertyObjectListener;
import com.acarter.scenemonitor.propertydescriptor.A_PropertyPage;
import com.jme.animation.SpatialTransformer;
import com.jme.scene.Controller;

/**
 * @author Carter
 *
 */
public class ControllerPropertyPage extends A_PropertyPage {
	
	/**  */
	private Controller controller = null;
	
	/**
	 * 
	 */
	public ControllerPropertyPage() {
		
		PropertySection section = new PropertySection("Controller");
		section.addProperty(new Property("Active", new BooleanPropertyObject()));
		section.addProperty(new Property("Repeat Type", new EnumPropertyObject<E_RepeatType>()));
		section.addProperty(new Property("Speed", new FloatPropertyObject()));
		section.addProperty(new Property("Min Time", new FloatPropertyObject()));
		section.addProperty(new Property("Max Time", new FloatPropertyObject()));
		
		section.setState(PropertySectionState.EXPANDED);
		
		model.addPropertySection(section);
	}
	
	/**
	 * @see com.acarter.scenemonitor.propertydescriptor.A_PropertyPage#updateInfo(com.acarter.propertytable.PropertyTableModel, java.lang.Object)
	 */
	@Override
	public void updateModel(PropertyTable table, Object object) {

		if(object instanceof Controller) {
			
			Controller controller = (Controller)object;
			
			if(this.controller == null || !this.controller.equals(controller)) {
				
				this.controller = controller;
				updateListeners(controller);
			}
		}
	}
	
	/**
	 * 
	 * @param table
	 * @param object
	 */
	@SuppressWarnings("unchecked")
	protected void updateListeners(final Controller controller) {
		
		/*if(controller instanceof SpatialTransformer) {
			SpatialTransformer		lcl_tx = (SpatialTransformer)controller;
			ArrayList<SpatialTransformer.PointInTime>		lcla_ptsInTime = lcl_tx.keyframes;
			
			for(SpatialTransformer.PointInTime lcl_ptInTime : lcla_ptsInTime) {
				System.out.println("time = " + lcl_ptInTime.time);
				
				for(int li_index = 0; li_index < lcl_ptInTime.look.length; li_index++) {
					System.out.println("\tlook " + li_index + " : tx = " + 
							lcl_ptInTime.look[li_index].getTranslation() + " : rot = " + lcl_ptInTime.look[li_index].getRotation() + 
							" : scale " + lcl_ptInTime.look[li_index].getScale());
				}
				
			}
		}*/
		
		BooleanPropertyObject active = (BooleanPropertyObject)model.getPropertySection("Controller").getProperty("Active").getPropertyObject();
		
		active.SetListener(new I_BooleanPropertyObjectListener() {

			public boolean readValue() {
				
				return controller.isActive();
			}

			public void saveValue(boolean value) {
				
				controller.setActive(value);
			}
		});		
		
		EnumPropertyObject<E_RepeatType> repeatType = (EnumPropertyObject<E_RepeatType>)model.getPropertySection("Controller").getProperty("Repeat Type").getPropertyObject();
		
		repeatType.SetListener(new I_EnumPropertyObjectListener<E_RepeatType>() {

			public E_RepeatType readValue() {
				
				return E_RepeatType.getConstant(controller.getRepeatType());
			}

			public void saveValue(E_RepeatType value) {
				
				controller.setRepeatType(value.getType());
			}
		});
		
		FloatPropertyObject speed = (FloatPropertyObject)model.getPropertySection("Controller").getProperty("Speed").getPropertyObject();
		
		speed.SetListener(new I_FloatPropertyObjectListener() {

			public float readValue() {
				
				return controller.getSpeed();
			}

			public void saveValue(float value) {
				
				controller.setSpeed(value);
			}
		});
		
		FloatPropertyObject minTime = (FloatPropertyObject)model.getPropertySection("Controller").getProperty("Min Time").getPropertyObject();
		
		minTime.SetListener(new I_FloatPropertyObjectListener() {

			public float readValue() {
				
				return controller.getMinTime();
			}

			public void saveValue(float value) {
				
				if(controller instanceof SpatialTransformer) {
					((SpatialTransformer)controller).setNewAnimationTimes(value, controller.getMaxTime());
				}
				else {
					controller.setMaxTime(value);
				}
			}
		});
		
		FloatPropertyObject maxTime = (FloatPropertyObject)model.getPropertySection("Controller").getProperty("Max Time").getPropertyObject();
		
		maxTime.SetListener(new I_FloatPropertyObjectListener() {

			public float readValue() {
				
				return controller.getMaxTime();
			}

			public void saveValue(float value) {
				if(controller instanceof SpatialTransformer) {
					((SpatialTransformer)controller).setNewAnimationTimes(controller.getMinTime(), value);
				}
				else {
					controller.setMaxTime(value);
				}
				
			}
		});
	}

	/**
	 * Enumerates the permissible controller repeat types.
	 * 
	 * @author Andrew Carter
	 */
	protected enum E_RepeatType {

		CLAMP("Clamp", 0),

		WRAP("Wrap", 1),

		CYCLE("Cycle", 2);

		/** String representation of the enum value */
		private String name;

		/** Integer value of the enum value */
		private int value;

		/**
		 * Private constructor.
		 * 
		 * @param value
		 *            String literal of the enum
		 */
		private E_RepeatType(String name, int value) {

			this.name = name;
			this.value = value;
		}

		/**
		 * Returns the enum constant matching the name string.
		 * 
		 * @param name
		 *            string value of enum constant
		 * @return matching enum constant or null
		 */
		public static E_RepeatType getConstant(String name) {

			for (E_RepeatType constant : E_RepeatType.values()) {

				if (constant.toString().compareToIgnoreCase(name) == 0)
					return constant;
			}

			return null;
		}

		/**
		 * Returns the enum constant matching the type value.
		 * 
		 * @param type
		 *            type value of enum constant
		 * @return matching enum constant or null
		 */
		public static E_RepeatType getConstant(int type) {

			for (E_RepeatType constant : E_RepeatType.values()) {

				if (constant.getType() == type)
					return constant;
			}

			return CLAMP;
		}

		/**
		 * Returns the string value of the constant.
		 */
		public String toString() {

			return name;
		}

		/**
		 * Returns the integer value of the constant.
		 * 
		 * @return
		 */
		public int getType() {

			return value;
		}
	}

}
